<?php
namespace Modules\Activity\Http\Controllers\Client\Leitai;

use Illuminate\Http\Request;
use Illuminate\Routing\Controller;

use \Modules\Activity\Entities\Leitai\Activity;
use \Modules\Activity\Entities\ActivityOrder as Order;

use Modules\Activity\Entities\TicketRecord;
use Modules\Activity\Entities\Ticket;
use Modules\User\Entities\User;
use Validator;
use ThrowException;
use Auth;
use DB;
use Cache;
use Setting;


// 抽赏订单
class OrderController extends Controller
{
    // 创建订单
    public function preview(Request $req)
    {
        $rule = [
            'activity_id' => ['required'],
            'total' =>  ['required']
        ];
        Validator::make($req->all(), $rule)->fails() && ThrowException::BadRequest();

        $user = Auth::requireLoginUser();

        // $cached = Cache::get($req->page_uuid) ?: ThrowException::Conflict('页面已失效，请刷新后重试~');


        // 擂台
        $activity = Activity::getEntity([
            'id' => $req->activity_id
        ]);

        // 购买总数
        $total = $req->total;

        // 检查是否超出限售
        $activity->checkSkuStock($total) || ThrowException::Conflict('库存不足~');

        // 检查是否超出限售
        // $activity->checkSaleLimit($total);

        // 检查次数限制
        // $activity->checkPerUserLimit($user, $total);

        $skuableMaps = [
            [
                'skuable' => $activity,
                'total' => $total
            ]
        ];

        if ( $activity->play_type == 4 || $activity->play_type == 5 ) {
            $this->playType4Chk($req, $user);
        }

        DB::beginTransaction();

        $coupon = NULL;
        if ($req->input('coupon_id'))
            $coupon = $user->coupons()->valid()->where('id', $req->coupon_id)->first();

        $isUseRedpack = $req->input('is_use_redpack');
        $isUseScore = $req->input('is_use_score');
        $order = Order::initWith($skuableMaps, $user, NULL, [
            'node' => $activity,
            'coupon' => $coupon,
            'is_use_redpack' => $isUseRedpack,
            'is_use_score' => $isUseScore,
            'is_visible' => 0,
        ]);

        // 返回订单内容
        return $order->generatePreviewResponse($user);
    }

    // 创建订单
    public function confirm(Request $req)
    {
        $rule = [
            'activity_id' => ['required'],
            'total' =>  ['required']
        ];
        Validator::make($req->all(), $rule)->fails() && ThrowException::BadRequest();

        $user = Auth::requireLoginUser();
        // 1秒内只能调1次此api
        Auth::limitTimeBeforeProcess($user, 'create_order', 1);

        // 擂台
        $activity = Activity::getEntity([
            'id' => $req->activity_id,
        ]);

        $activity->status == 1 || ThrowException::Conflict('活动已下架~');
        // 购买总数
        $total = $req->total;

        // 检查是否超出限售
        $activity->checkSkuStock($total) || ThrowException::Conflict('库存不足~');

        $skuableMaps = [
            [
                'skuable' => $activity,
                'total' => $total
            ]
        ];

        $is_last = $activity->checkSkuStockAll($total);
        // if ( $is_last && $activity->last_open_time > time() && in_array($activity->play_type, [2, 3]) ){
        if ( $activity->last_open_time > time() && in_array($activity->play_type, [2, 3, 6]) ){
            // 榜一保护期
            $bang1=DB::table('orders')->where(array('node_id' => $req->activity_id, 'node_type'=> 'leitai'))->groupBy('user_id')->orderBy('totals', 'desc')->first(
                array(
                    \DB::raw('SUM(sku_total) as totals'),  'user_id'
                )
            );

            if ( $user->id != $bang1->user_id ){
                $p = round(($activity->last_open_time - time())/60);
                echo json_encode(array('code'=>222, 'msg'=>"当前时间为榜一保护期，剩余时间：$p 分钟。"));die;
            }
        }

        if ( $activity->play_type == 4 || $activity->play_type == 5 ) {
            $this->playType4Chk($req, $user);
        }

        if ( $activity->play_type == 7 ) {
            $has_chk = $this->playType7Chk($req, $user);
            $max = @Setting::get('sys_leitai_max_orders')?:5;

            if ( $has_chk + $total > $max ){
                echo json_encode(array('code'=>203, 'msg'=>"单人最多可开 $max 盒，您已超限。"));die;
            }
        }
        DB::beginTransaction();

        $coupon = NULL;
        if ($req->input('coupon_id'))
            $coupon = $user->coupons()->valid()->where('id', $req->coupon_id)->first();

        $isUseRedpack = $req->input('is_use_redpack');
        $isUseScore = $req->input('is_use_score');

        $sharer = 0;
        if ( $req->input('sharer') ){
            $s = DB::table('users')->where('uuid', $req->sharer)->first();
            $s_init = object_to_array($s);
            $sharer = $s_init['id'];
        }

        $order = Order::initWith($skuableMaps, $user, NULL, [
            'node' => $activity,
            'coupon' => $coupon,
            'is_use_redpack' => $isUseRedpack,
            'is_use_score' => $isUseScore,
            'is_visible' => 0,
            'sharer' => $sharer,
        ]);

        $this->base_sku = $activity;

        // 使用免费次数兑换
        if ($req->input('is_use_free_ticket') && $req->input('ticket_id') && $total === 1) {
            $ticket = Ticket::getEntity([
                'id' => $req->ticket_id
            ]);

            $newStock = $ticket->stock - $total;

            $newUseTotal = $ticket->used_total;
            $newUseTotal += $total;

            if ($newStock < 0) {
                DB::rollBack();
                return false;
            }

            $ticket->update([
                'stock' => $newStock,
                'total' => $ticket->total + $total,
                'used_total' => $newUseTotal,
            ]);

            TicketRecord::create([
                'user_id' => $user->id,
                'node_id' => $activity->id,
                'node_type' => 'leitai',
                'node_uuid' => $activity->uuid,
                'type' => 2,
                'total' => $total,
                'after_total' => $newStock,
                'description' => '使用扣除'
            ]);

            $order->useFreeTicket();
        }


        $cacheKey = 'order_create' . $activity->id . '_' . $user->id ;

        // 检测当前用户是否有订单在创建
        if ( $activity->play_type == 4 || $activity->play_type == 5 ) {
            if (Cache::get($cacheKey)) {
                echo json_encode(array('code'=>203, 'msg'=>'已存在消费记录，不可重复购买。'));die;
            }
        }


        // 缓存当前正在开奖，缓存时间1000s
        Cache::put($cacheKey, 1, 10000);

        $order->createAll();

        DB::commit();

        // 返回订单内容
        $res = $order->generateResponse();

        if ( $activity->play_type == 4 && $res['is_need_pay'] != 1 ) {
            // echo json_encode(array('code'=>201, 'msg'=>'购买成功，等待开奖~', 'data'=>array('order_id'=>$order->id)));die;
        }
        return $res;
    }

    public function playType4Chk($req, $user)
    {
        // 验证是不是超额售卖了

        // 验证是不是已卖过了 一个人一个盒子只能开一次
        $has_chk_arr = array(
            'node_id' => $req->activity_id,
            'node_type' => 'leitai',
            'user_id' => $user->id,
        );
        $has_chk =DB::table('orders')->where($has_chk_arr)->first();
        $has_chk = object_to_array($has_chk);
        if ( isset($has_chk['id']) && $has_chk['id'] > 0 && ($has_chk['pay_type'] || $has_chk['user_id'] == 18575) ){
            echo json_encode(array('code'=>203, 'msg'=>'已存在消费记录，不可重复购买。'));die;
        }
    }

    public function playType7Chk($req, $user)
    {
        $has_chk_arr = array(
            'node_id' => $req->activity_id,
            'node_type' => 'leitai',
            'user_id' => $user->id,
        );
        $has_chk =DB::table('orders')->where($has_chk_arr)->whereNotNull('pay_type')->get(\DB::raw('sum(sku_total) total'))->first();
        return @$has_chk->total ? $has_chk->total : 0;
    }

    // 试一试
    public function try(Request $req)
    {
        $rule = [
            'activity_id' => ['required'],
            'total' =>  ['required']
        ];
        Validator::make($req->all(), $rule)->fails() && ThrowException::BadRequest();

        $user = Auth::requireLoginUser();

        // $cached = Cache::get($req->page_uuid) ?: ThrowException::Conflict('页面已失效，请刷新后重试~');

        // 福袋
        $activity = Activity::getEntity([
            'id' => $req->activity_id
        ]);

        // 购买总数
        $total = $req->total;

        // 仅仅
        DB::beginTransaction();

        // 取出sku
        $skuMaps = $activity->pickLuckySkusForTry($total, $user, null);

        $list = [];

        // 此处不要提交到数据库保存
        foreach ($skuMaps as $skuMap) {
            $sku = $skuMap['skuable'];
            array_push($list, [
                "title" => $sku->title,
                "number" => $sku->number,
                "thumb" => $sku->thumb,
                "money_price" => $sku->money_price,       // 价值 (人民币)
                "total" => $skuMap['total'],                 // 中奖数量
            ]);
        }

        $uuid = 'try_' . uniqid();

        $cached = [
            'sku_type' => 'leitai_sku',
            'sku_id' => $skuMaps[0]['skuable']->id,
            'skus' => $list
        ];
        Cache::put($uuid, $cached, 1800);

        return [
            'package_uuid' => $uuid,
            // 'skus' => $list
        ];

    }


    //*********** 机器人自动下单 开始 ************
    public function job(){
        //查询出所有等待执行的数据
        $DangTime = date('H')*1;
        $list =DB::table('leitai_cron_skus')->where([
            ['end_time', '>=', $DangTime],
            ['start_time', '<=', $DangTime],
        ])->get()->toArray();

        if ( $list ){
            // 本次需要执行的链接
            foreach ($list as $key => $value) {
                $this->asyncRequest('https://api.cqblyn.com/leitaiCron/cronBegin', array('title'=>$value->title));
            }
            die(date('Y-m-d H:i:s').' 机器人: 我整完啦...');
        }else{
            die(date('Y-m-d H:i:s').' 机器人: 没有任务哈...');
        }
    }

    public function asyncRequest($url='', $data=array())
    {
        if (is_array($data)) {
            $data = http_build_query($data, null, '&');
        }
        $ch = curl_init();
        curl_setopt($ch, CURLOPT_URL, $url);
        curl_setopt($ch, CURLOPT_POST, 1);
        curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
        curl_setopt($ch, CURLOPT_TIMEOUT, 1);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
        $result['response'] = curl_exec($ch);
        $result['httpCode'] = curl_getinfo($ch, CURLINFO_HTTP_CODE);
        return $result;

    }

    public function cronBeginChk(Request $req)
    {
        $activity_title = $req->title;
//        $arr = array();
//        $arr['run_time'] = date('Y-m-d H:i:s');
//        $arr['title'] = $activity_title;
//        DB::table('leitai_cron_skus')->insert($arr);

        // 没开完不执行下面方法
        // 上次开奖时间超过10分钟  重新写入此次需要开的盒子
        $list =DB::table('leitai_cron_chk')->where('activity_title', $activity_title)->first();

        if ( $list && $list->next_time > time() && $list->create_time_str > time()-60*10 ){
            die('title:'.$activity_title.' 未到下次执行时间...'. date('Y-m-d H:i:s', $list->next_time) );
        }

        // 占着线程
        DB::update('update leitai_cron_chk set next_time = '.(time()+50).'  where activity_title = ? ',[$activity_title]);

        $res =DB::table('leitai_data_sum')->whereNotNull('run_time')->where([
            ['title', '=', $activity_title],
            ['run_time', '<>', 0],
        ])->first();

        if ( !$res ) {
            DB::table('leitai_cron_chk')->where([
                ['activity_title', '=', $activity_title]
            ])->delete();
            die('title:' . $activity_title . ' 没有待执行的任务...');
        }


        // 插入这次需要开完的盒子

        $c = false;
        if ( $res->play_type == 4 ){
            // 空空奖玩法 当前保底奖有库存的
            $c = DB::select("select activity_id from leitai_last_skus where activity_id IN ( select id from leitai_activity where title = '{$activity_title}' 
                        and status = 1 and play_type = 4 and stock > 0) and stock > 0 and last_prize_type = 3 order by activity_id asc limit 1");
        }
        if ( $res->play_type == 5 ){
            //PK奖玩法 当前基础奖有库存的
            $c = DB::select("select activity_id from leitai_skus where activity_id IN ( select id from leitai_activity where title = '{$activity_title}'
                        and status = 1 and play_type = 5 and stock > 0 ) and stock > 0 order by activity_id asc limit 1");
        }


        if ( $c ){
            $arr = array();
            foreach ( $c as $k => $v ){
                $arr[$k]['create_time'] = date('Y-m-d H:i:s');
                $arr[$k]['create_time_str'] = time();
                $arr[$k]['next_time'] = time()+3600;
                $arr[$k]['play_type'] = $res->play_type;
                $arr[$k]['activity_type'] = 'leitai';
                $arr[$k]['activity_id'] = $v->activity_id;
                $arr[$k]['activity_title'] = $activity_title;
            }
            DB::table('leitai_cron_chk')->where([
                ['activity_title', '=', $activity_title]
            ])->delete();
            DB::table('leitai_cron_chk')->insert($arr);

            foreach ( $c as $k => $v ){
                self::cronBegin($v->activity_id, $res->run_time);
                echo $activity_title.' '.$v->activity_id.' DONE...'."\r\n";
            }
        }
        die($activity_title.' DONE...');
    }

    // 原任务 备份
    public function cronBeginChk_backup(Request $req)
    {
        $activity_title = $req->title;
        // 没开完不执行下面方法
        // 上次开奖时间超过30分钟  重新写入此次需要开的盒子
        $list =DB::table('leitai_cron_chk')->where([
            ['create_time_str', '>', time()-60*30],
            ['activity_title', '=', $activity_title],
        ])->get()->toArray();

        if ( $list ) die('title:'.$activity_title.' 等待上一个任务执行结束...');
        DB::table('leitai_cron_chk')->where([
            ['activity_title', '=', $activity_title]
        ])->delete();

        $DangTime = date('H')*1;
        $res =DB::table('leitai_cron_skus')->where([
            ['end_time', '>=', $DangTime],
            ['start_time', '<=', $DangTime],
            ['title', '=', $activity_title],
        ])->get()->toArray();

        if ( !$res ) die('title:'.$activity_title.' 没有待执行的任务...');
        $start = time();
        foreach ( $res as $kay => $value ){
            if ( $value->run_time > 60 ){
                if ( date('i')%($value->run_time-60) != 0 ) return;
            }

            // 插入这次需要开完的盒子
            if ( $value->run_time <= 60 ){
                $sleep_time = bcdiv('60',$value->run_time);//根据设置时间来计算一分钟循环几次
            }else{
                $sleep_time = 1;
            }

            $c = false;
            if ( $value->play_type == 4 ){
                // 空空奖玩法 当前保底奖有库存的
                /*
                $c = DB::select("select activity_id from leitai_last_skus where activity_id IN ( select id from leitai_activity where title = '{$value->title}'
                        and status = 1 and play_type = 4 and stock > 0) and stock > 0 and last_prize_type = 3 order by activity_id asc limit $sleep_time");
                */

                $c = DB::select("select activity_id from leitai_last_skus where activity_id IN ( select id from leitai_activity where title = '{$value->title}' 
                        and status = 1 and play_type = 4 and stock > 0) and stock > 0 and last_prize_type = 3 order by activity_id asc limit 1");
            }
            if ( $value->play_type == 5 ){
                //PK奖玩法 当前基础奖有库存的
                /*
                $c = DB::select("select activity_id from leitai_skus where activity_id IN ( select id from leitai_activity where title = '{$value->title}'
                        and status = 1 and play_type = 5 and stock > 0 ) and stock > 0 order by activity_id asc limit $sleep_time");
                */

                $c = DB::select("select activity_id from leitai_skus where activity_id IN ( select id from leitai_activity where title = '{$value->title}'
                        and status = 1 and play_type = 5 and stock > 0 ) and stock > 0 order by activity_id asc limit 1");
            }

            if ( $c ){
                $arr = array();
                foreach ( $c as $k => $v ){
                    $arr[$k]['create_time'] = date('Y-m-d H:i:s');
                    $arr[$k]['create_time_str'] = time();
                    $arr[$k]['play_type'] = $value->play_type;
                    $arr[$k]['activity_type'] = 'leitai';
                    $arr[$k]['activity_id'] = $v->activity_id;
                    $arr[$k]['activity_title'] = $activity_title;
                }
                DB::table('leitai_cron_chk')->insert($arr);

                foreach ( $c as $k => $v ){
                    if ( $value->run_time <= 60 ){
                        $start_limit = $start + $k * $value->run_time-1;
                    }else{
                        $start_limit = 0;
                    }
                    // 每秒执行 时间随机
                    if ( self::timeLimitChk($start_limit) || 1 ){
                        self::cronBegin($v->activity_id, $value->run_time);

                        DB::table('leitai_cron_chk')->where([
                            'activity_type' => 'leitai',
                            'activity_id' => $v->activity_id,
                        ])->delete();

                        echo $activity_title.' '.$v->activity_id.' DONE...'."\r\n";
                    }
                }
            }
            die($activity_title.' DONE...');
        }

        die('ERR & DONE...');
    }

    public function cronBegin($activity_id, $run_time=0)
    {
        // 擂台
        $activity = Activity::getEntity([
            'id' => $activity_id
        ]);

        // 购买总数
        $total = 1;

        if ( $activity->play_type == 4 ){
            // 空空奖玩法检查是否超出限售
            if ( !$activity->checkLastSkuStock($total) ){
                return true;
            }
        }else if ( $activity->play_type ==5 ){
            if ( !$activity->checkSkuStock($total) ){
                return true;
            }
        }else{
            // 不是擂台玩法
            return true;
        }

        $skuableMaps = [
            [
                'skuable' => $activity,
                'total' => $total
            ]
        ];

        $has_chk_arr = array(
            'node_id' => $activity_id,
            'node_type' => 'leitai',
        );
        $has_chk =DB::table('orders')->where($has_chk_arr)->whereNotNull('pay_type')->get(
            \DB::raw('user_id')
        )->toArray();
        $user_has = array_column($has_chk, 'user_id');

        $user_id = self::getRandUserID($user_has);
        $user = User::getEntity([
            'id' => $user_id
        ]);

        if ( $run_time ){
            $run_time_arr = str_replace(' ', '', $run_time);
            $run_time_arr = str_replace('，', ',', $run_time_arr);
            $run_time_arr = explode(',', $run_time_arr);
            if ( array_sum($user_has) > 10000 ){
                // 当前箱子存在真实用户已在车上，每个机器人上车时间随机延迟 2-6 秒
                $n1 = $run_time_arr[0] - 1;
                $n2 = $run_time_arr[1] - 1;
                $s=rand($n1, $n2);
            }else{
                $n1 = $run_time_arr[2] - 1;
                $n2 = $run_time_arr[3] - 1;
                $s=rand($n1, $n2);
            }
            $s = max($s, 0);
//            echo "下次执行 延迟: ".($s+1)." s";
        }else{
            die('run_time 异常');
        }

        DB::beginTransaction();

        $coupon = NULL;

        $isUseRedpack = NULL;
        $isUseScore = NULL;

        $sharer = 0;

        $order = Order::initWith($skuableMaps, $user, NULL, [
            'node' => $activity,
            'coupon' => $coupon,
            'is_use_redpack' => $isUseRedpack,
            'is_use_score' => $isUseScore,
            'is_visible' => 0,
            'sharer' => $sharer,
        ]);

        $order->pay_money_price = 0;
        $order->remark = 'job order';
        $order->brokerage_status = 1;
        $order->share_status = 1;
        $this->base_sku = $activity;
        $order->createAll();
        DB::commit();
        (new \Modules\Asset\Http\Controllers\Client\V1\PackageController)->getOrderPrize($order->id, $user);

        DB::update('update leitai_cron_chk set next_time = '.(time()+$s).'  where activity_title = ? ',[$activity->title]);
        return false;
    }

    public function getRandUserID($chk=array())
    {
        $user_id = rand(1,134);
        if ( in_array($user_id, $chk) ){
            return self::getRandUserID($chk);
        }
        return $user_id;
    }

    public function timeLimitChk($time)
    {
        if ( $time <= time() ){
            return true;
        }else{
            sleep(1);
            return self::timeLimitChk($time);
        }
    }

    //*********** 机器人自动下单 结束 ************

    public function leitaiDataSum($i=0)
    {
        $sql = "SELECT
                    title,
                    money_price,
                    score_price,
                    max( id ) id,
                    max( uuid ) uuid,
                    count( id ) cnt,
                    min( created_at ) created_at,
                    min( thumb ) thumb,
                    status,
                    play_type,
                    max( list_weight ) list_weight,
                    max(is_invite_enabled) is_invite_enabled,
                    max(is_share_enabled) is_share_enabled,
                    max(run_time) run_time
                FROM
                    leitai_activity
                GROUP BY
                    title,
                    money_price,
                    score_price,
                    play_type,
                    STATUS 
                ORDER BY
                    list_weight DESC,
                    created_at DESC";

        $res = DB::select($sql);

        if ( $res ){
            foreach ( $res as &$v ){
                $v->create_time = date('Y-m-d H:i:s');
                $v->stock = 0;
                $v->sales = 0;
                $v->now_id = 0;
                $stock_res_id = DB::table('leitai_activity')->where('title', $v->title)->get('id')->toArray();
                $ids = array_column($stock_res_id, 'id');

                $stock_res = DB::table('leitai_skus')->whereIN('activity_id', $ids)->get(\DB::raw('sum(stock) stock, sum(sales) sales'))->first();
                unset($ids);
                if ( $stock_res ){
                    $v->stock = $stock_res->stock;
                    $v->sales = $stock_res->sales;
                }
            }

            $res = object_to_array($res);
            DB::table("leitai_data_sum")->delete();
            DB::table("leitai_data_sum")->insert($res);
        }

        if ( date('s') < 35 && $i < 5 ){
            sleep(10);
            $i++;
            return self::leitaiDataSum($i);
        }
        echo date('Y-m-d H:i:s');
        die;
    }

    public function leitaiOpenChk()
    {
        $s = date('Y-m-d H:i:s', strtotime('-20 min'));
        $e = date('Y-m-d H:i:s', strtotime('-10 min'));
        $sql = "SELECT
                    node_id
                FROM
                    orders
                where 
                    created_at between '$s' and '$e'
                    AND remark is null
	                AND node_type = 'leitai' 
                GROUP BY
                    node_id
                ";

        $res = DB::select($sql);

        if ( $res ){
            foreach ( $res as $k => $v ){
                (new \Modules\Asset\Http\Controllers\Client\V1\PackageController)->playType4($v->node_id);
            }
        }
    }

    public function openBox(Request $req)
    {
        if ( $req->play_type == 4 ){
            (new \Modules\Asset\Http\Controllers\Client\V1\PackageController)->playType4($req->id, 2);
        }
        if ( $req->play_type == 5 ){
            (new \Modules\Asset\Http\Controllers\Client\V1\PackageController)->playType5($req->id);
        }
    }

    public function clear()
    {
        if ( date('d')%5 != 0 ) return;
        $d_10 = date('Y-m-d', strtotime('-10 day'));
        $order = DB::select("select node_id, node_uuid, max(user_id) max_user_id, count(*) cnt from orders where node_type = 'leitai' and created_at < '$d_10' group by node_uuid, node_id having max_user_id < 5000");
        $activity_id = array_column($order, 'node_id');
        $sku = DB::table('leitai_last_skus')->whereIn('activity_id', $activity_id)->where('last_prize_type', 3)->get()->toArray();
        $activity_id = array_column($sku, 'activity_id');

        if ( $activity_id ){
            DB::table('package_assets')->whereIn('node_id', $activity_id)->where('node_type', 'leitai')->delete();
            DB::table('package_skus')->whereIn('node_id', $activity_id)->where('node_type', 'leitai')->delete();
            DB::table('orders')->whereIn('node_id', $activity_id)->where('node_type', 'leitai')->delete();

            DB::table('leitai_activity')->whereIn('id', $activity_id)->delete();
            DB::table('leitai_last_skus')->whereIn('activity_id', $activity_id)->delete();
            DB::table('leitai_skus')->whereIn('activity_id', $activity_id)->delete();
        }
    }


}
